﻿// Copyright 2009 William P. Hickey Jr. and William U. Walker
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//     
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//  
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using AgwpePort;

namespace CSReporter
{
    /// <summary>
    /// Abstract class containing the algorithm used to transmit APRS messages.
    /// </summary>
    abstract class MsgObject
    {
        protected int startDelay;
        protected int loopDelay;
        protected string toCall;
        protected string callSign;
        protected string digiPath;
        protected byte[] message;
        protected string aprsMsgNumber;

        public string AprsMsgNumber
        {
            set { aprsMsgNumber = value == null ? null:value.Trim().ToUpper(); }
        }

        public string CallSign
        {
            get { return callSign; }
            set { callSign = value == null ? null : value.Trim().ToUpper(); }
        }

        public string ToCall
        {
            get { return toCall; }
            set { toCall = value == null ? null : value.Trim().ToUpper(); }
        }

        public byte[] Message
        {
            get { return message; }
            set { message = value; }
        }

        public int StartDelay
        {
            get { return startDelay; }
            set { startDelay = value; }
        }

        public int LoopDelay
        {
            get { return loopDelay; }
            set { loopDelay = value; }
        }

        public string DigiPath
        {
            get { return digiPath; }
            set { digiPath = value == null ? null : value.Trim().ToUpper(); }
        }

        public void SendMessage()
        {
            try
            {
                MessageList msgStatus = MessageList.GetMessageList();

                // Make sure all required data is available.
                if (toCall.Trim().Length > 0 & callSign.Trim().Length > 0 & message != null)
                {
                    // Sleep for two seconds to space message transmissions.
                    Thread.Sleep(startDelay * 1000);
                    // Send the APRS message.
                    if (TransmitMessage() == false)
                        // Terminate the thread if there is a problem transmitting the message.
                        return;
                    // Transmit the message no more than 10 more times.
                    // The delay between transmissions is doubled on each loop.
                    for (int seconds = loopDelay; seconds <= (loopDelay * 512); seconds = seconds * 2)
                    {
                        // Transmit delay loop.
                        for (int count = seconds; count > 0; count--)
                        {
                            // Sleep for one second.
                            Thread.Sleep(1000);
                            // Terminate the thread if there is no connection to a TNC or TNC control service.
                            if (!IsOpen())
                                return;
                        }
                        // Terminate the thread if the message has been acknowledged.
                        if (msgStatus.IsMessageAcked(toCall.Trim(), callSign.Trim(), aprsMsgNumber))
                            return;
                        if (TransmitMessage() == false)
                            // Terminate the thread if there is a problem transmitting the message.
                            return;
                    }
                }
            }
            // If an exception is thrown, let the thread end quietly.    
            catch { }
        }

        protected abstract bool TransmitMessage();
        protected abstract bool IsOpen();
    }

    /// <summary>
    /// Extends the MsgObject class to provide specific functionality for transmitting APRS messages 
    /// using an AGW Packet Engine service.
    /// </summary>
    class AgwpeMessage : MsgObject
    {
        private AgwpePort.AgwpePort agwpePort;

        public AgwpeMessage(AgwpePort.AgwpePort agwpePort, int startDelay, int loopDelay, string callSign, string toCall, string viaList, byte[] message)
        {
            this.StartDelay = startDelay;
            this.LoopDelay = loopDelay;
            this.ToCall = toCall.Trim().ToUpper();
            this.CallSign = callSign.Trim().ToUpper();
            this.DigiPath = viaList.Trim().ToUpper();
            this.Message = message;
            this.AprsMsgNumber = "";
            this.agwpePort = agwpePort;
        }

        protected override bool TransmitMessage()
        {
            // If we still have a AGWPE connection...
            if (agwpePort.IsOpen())
            {
                // Send the APRS message.
                agwpePort.SendUnproto(agwpePort.RadioPort, callSign, toCall, message, digiPath.Split(','));
                // Return a true value;
                return true;
            }
            // Return a value of false if there is no connection to AGWPE.
            return false;
        }

        protected override bool IsOpen()
        {
            // Return a value indicating the state of the AGWPE connection.
            return agwpePort.IsOpen();
        }
    }
}
